import querystring from 'querystring';
import {
    wait,
    isArray,
    isFunction,
    getStorage,
    isPlainObject,
    isString,
} from '@/lib/utils';
import {
    API_URL,
    KEY_AUTH_TOKEN,
    LOGIN_STATUS,
} from '@/lib/constant';
import { login } from '@/lib/script/login';
import store from '@/store';
import { router } from '@/router';
import { Api, NavigateOptions } from '@/types/api';
import { RawLocation } from 'vue-router';

const identity = _ => _;

// 转换成promise
function promisify(name) {
    return obj => new Promise((resolve, reject) => {
        obj = obj || {};
        if (obj.success) {
            const old = obj.success;
            obj.success = async (res) => {
                await old(res);
                resolve(res);
            };
        } else {
            obj.success = resolve;
        }
        const old = obj.fail;
        obj.fail = async (res) => {
            if (old) {
                await old(res);
            }
            // console.log(`${name} fail`, res);
            reject(res);
        };
        // @ts-ignore
        wx[name](obj);
    });
}

// api
const apiNames = [
    'login',
    'getUserInfo',
    'getUserProfile',
    'setStorage',
    'getStorage',
    'request',
    'getSystemInfo',
    'checkSession',
    'getImageInfo',
    'saveImageToPhotosAlbum',
    'downloadFile',
    'getSetting',
    'openSetting',
    'authorize',
    'showToast',
    'hideToast',
    'showLoading',
    'hideLoading',
    'chooseImage',
    'uploadFile',
    'scanCode',
    'chooseLocation',
    'openLocation',
    'pageScrollTo',
    'requestPayment',
    'chooseImage',
    'getClipboardData',
    'setClipboardData',
    'canvasToTempFilePath',
    'saveFile',
    'requestSubscribeMessage',
];
// @ts-ignore
export const api: Api = {};
apiNames.forEach((name) => {
    api[name] = promisify(name);
});

// 对于sync进行处理
api.setStorageSync = wx.setStorageSync;
api.getStorageSync = wx.getStorageSync;

// 处理request
api._request = api.request;
api.get = api.request = async function request(obj) {
    // console.log(`[request] ${obj.url}`, obj);
    const jwt = await getStorage(KEY_AUTH_TOKEN);

    if (obj.url && obj.url.startsWith('/')) {
        obj.url = API_URL + obj.url;
    }

    if (jwt) {
        if (obj.header) {
            obj.header.Authorization = 'Bearer ' + jwt;
        } else {
            obj.header = {
                Authorization: 'Bearer ' + jwt,
            };
        }
    }

    if (obj.header) {
        obj.header.accept = 'application/json';
        obj.header['X-Requested-With'] = 'XMLHttpRequest';
    } else {
        obj.header = {
            accept: 'application/json',
            'X-Requested-With': 'XMLHttpRequest',
        };
    }
    // todo: 需要考虑去掉这段代码，或者优化它。1. 无法处理数组，会删除null的字段
    // 清理data中的数据
    if (obj.data) {
        const data = {};
        Object.keys(obj.data).forEach((key) => {
            if (obj.data[key] !== null && obj.data[key] !== undefined) {
                data[key] = obj.data[key];
            }
        });
        obj.data = data;
    }
    obj.fail = function() {
        // console.log('fail');
    }
    const res = await api._request(obj).catch((err) => {
        // console.log('err', err);
        return err;
    });
    // console.log(`[response] ${obj.url}`, res);
    // console.log('target19-1', res);
    // 当前登录失效，需要重新登录
    if (res.statusCode === 401 || res.data.status === 1001) {
        store.commit('auth/setLogin', LOGIN_STATUS.LOGOUT);
        const result = await login(true);
        if (isString(result)) {
            if (obj.header) {
                obj.header.Authorization = 'Bearer ' + result;
            } else {
                obj.header = {
                    Authorization: 'Bearer ' + result,
                };
            }
        }
        return api._request(obj);
    }
    // 请求出现失败将再次请求
    if (res.errMsg.indexOf('request:fail') >= 0) {
        return api._request(obj);
    }
    return res;
};
api.post = function post(obj) {
    obj.method = 'POST';
    return api.request(obj);
};
api.put = function put(obj) {
    obj.method = 'PUT';
    return api.request(obj);
};
api.delete = function del(obj) {
    obj.method = 'DELETE';
    return api.request(obj);
};

// 处理授权逻辑
api._saveImageToPhotosAlbum = api.saveImageToPhotosAlbum;
api.saveImageToPhotosAlbum = async function (obj) {
    const settingRes = await api.getSetting();
    if (!settingRes.authSetting['scope.writePhotosAlbum']) {
        wx.showToast({
            title: '为了保存图片，我们可能需要一些授权',
            icon: 'none',
            duration: 2000,
        });
        await wait(2000);

        const authRes = await api.authorize({
            scope: 'scope.writePhotosAlbum',
        }).catch(errRes => errRes);

        if (authRes.errMsg !== 'authorize:ok') {
            wx.showToast({
                title: '获取权限失败，请在设置窗口重新设置授权。',
                icon: 'none',
            });

            const openRes = await api.openSetting();

            // 成功授权
            if (openRes.authSetting['scope.writePhotosAlbum']) {
                return api._saveImageToPhotosAlbum(obj);
            }

            return;
        }

        // 获得授权
        return api._saveImageToPhotosAlbum(obj);
    }
    return api._saveImageToPhotosAlbum(obj);
};

// 处理uploadFile
api._uploadFile = api.uploadFile;
api.uploadFile = async function (obj) {
    const jwt = await getStorage(KEY_AUTH_TOKEN);

    if (!obj.url) {
        obj.url = `${API_URL}/upload`;
    }
    if (jwt) {
        if (obj.header) {
            obj.header.Authorization = `Bearer ${jwt}`;
        } else {
            obj.header = {
                Authorization: `Bearer ${jwt}`,
            };
        }
    }

    if (obj.header) {
        obj.header.accept = 'application/json';
        obj.header['X-Requested-With'] = 'XMLHttpRequest';
    } else {
        obj.header = {
            accept: 'application/json',
            'X-Requested-With': 'XMLHttpRequest',
        };
    }
    return api._uploadFile(obj);
};

/**
 * 执行auth检查包裹
 * @param {} options
 *  - name
 *  - scope 需要检查的scope
 *  - hintToastOption
 *  - wait 等待一段时间
 *  - settingToastOption
 *  - settingUrl 'setting': 表示到设置页面, { url }表示要跳转的链接, function: 需要执行的函数
 */
function authCheckWrap(options) {
    if (!api[options.name]) {
        return;
    }
    const origin = api[`_${options.name}`] = api[options.name];
    // todo: 这里的obj的类型没有办法确定
    api[options.name] = async function (obj) {
        const settingRes = await api.getSetting().catch(err => err);
        if (!settingRes.authSetting[options.scope]) {
            if (options.hintToastOption) {
                wx.showToast(options.hintToastOption);
            }
            if (options.wait) {
                await wait(options.wait);
            }
            const authRes = await api.authorize({
                scope: options.scope,
            }).catch(errRes => errRes);
            if (authRes.errMsg !== 'authorize:ok') {
                if (options.settingToastOption) {
                    wx.showToast(options.settingToastOption);
                }

                const settingUrl = obj.settingUrl || options.settingUrl || 'setting';
                if (settingUrl === 'setting') {
                    // 到设置页面
                    const openRes = await api.openSetting();
                    // 成功授权
                    if (openRes.authSetting[options.scope]) {
                        return origin(obj);
                    }
                } else if (isFunction(settingUrl)) {
                    settingUrl(obj.query);
                } else if (isPlainObject(settingUrl)) {
                    wx.navigateTo(Object.assign({}, options.settingUrl));
                }

                return;
            }
            // 获得授权
            return origin(obj);
        }

        return origin(obj);
    };
}

// 跳转用户信息授权
authCheckWrap({
    name: 'getUserInfo',
    scope: 'scope.userInfo',
});

authCheckWrap({
    name: 'chooseLocation',
    scope: 'scope.userLocation',
});

/**
 * @return querystring文本
 */
export function parseNavigationObj(obj: NavigateOptions) {
    // 存在?的内容
    const parts = obj.url ? obj.url.split('?') : [];
    let query = {};
    if (parts.length > 1) {
        query = querystring.parse(decodeURIComponent(parts[1]));
    }
    if (obj.query) {
        Object.assign(query, obj.query);
    }
    const keys = Object.keys(query);
    // 处理array数据
    for (let i = 0, len = keys.length; i < len; i++) {
        const key = keys[i];
        if (isArray(query[key])) {
            query[key] = JSON.stringify(query[key]);
        }
        query[key] = decodeURIComponent(query[key]);
    }
    return querystring.stringify(query, '&', '=', { encodeURIComponent: identity });
}

// 对于navigate导航进行加强
api.redirectTo = function(obj) {
    const str = parseNavigationObj(obj);
    if (str) {
        obj.url += (`?${str}`);
    }
    wx.redirectTo(obj);
};

api.reLaunch = function(obj) {
    const str = parseNavigationObj(obj);
    if (str) {
        obj.url += (`?${str}`);
    }
    wx.reLaunch(obj);
};

api.navigateTo = function(obj: NavigateOptions) {
    const str = parseNavigationObj(obj);
    if (str) {
        obj.url += (`?${str}`);
    }

    // 替代router hook
    const route = router.resolve(obj.query?.targeturl as string).route;
    const meta = route?.meta;
    if (meta && meta.needInfo) {
        const basicInfo = store.state.user.basicInfo;
        if (!basicInfo.nickname || !basicInfo.avatar) {
            // 不允许进入
            store.commit('auth/showUserInfo', true);
            store.commit('auth/setBindMobileFrom', route);
            return;
        } else if (!basicInfo.mobile) {
            // 不允许进入
            store.commit('auth/showBindMobile', true);
            store.commit('auth/setBindMobileFrom', route);
            return;
        }
    }

    wx.navigateTo(obj);
};

api.push = function(location: RawLocation) {
    api.navigateTo({
        url: '/pages/main/index',
        query: {
            type: 'jump',
            targeturl: router.resolve(location).route.fullPath,
        },
    });
}

api.replace = function(location: RawLocation) {
    api.redirectTo({
        url: '/pages/main/index',
        query: {
            type: 'jump',
            targeturl: router.resolve(location).route.fullPath,
        },
    });
}

api.launch = function(location: RawLocation) {
    api.reLaunch({
        url: '/pages/main/index',
        query: {
            type: 'jump',
            targeturl: router.resolve(location).route.fullPath,
        },
    });
}
